//
//  ECSUIBuilder.m
//  ECS DevelopKit
//
//  Created by LittoCats on 8/26/14.
//  Copyright (c) 2014 Littocats. All rights reserved.
//

#import "ECSUIBuilder.h"
#import "ECSUtilities.h"
#import "ECSObjectAttributeWrapper.h"
#import <objc/runtime.h>
#import <objc/message.h>

@implementation ECSUIBuilder

+ (UIView *)viewWithAttributes:(NSDictionary *)attributes context:(ECSScriptContext *)context
{
    //解析类型
    //如果以小写字母开头，则需要从默认的 view 影射表中查找相应的类型
    //如果 type 不存在或者为空，则 type = @"UIView"
    NSString *type = [attributes objectForKey:@"type"];
    if (type.length && [type characterAtIndex:0] >= 'a') {
        static NSDictionary *ecsDefaultViewTable = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSString *ecs_ui_builder_default_view_table = [[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ecs_ui_builder_default_view_table"
                                                                                                                                   ofType:@"js"]
                                                                                          encoding:NSUTF8StringEncoding
                                                                                             error:nil];
            NSAssert(ecs_ui_builder_default_view_table, @"[ECSUIBuilder] error : ecs_ui_builder_default_view_table not exist .");
            ecsDefaultViewTable = [[UIApplication sharedApplication].ecsContext evaluateScript:ecs_ui_builder_default_view_table];
        });
        type = [ecsDefaultViewTable objectForKey:type];
    }
    if (!type || [type isEmpty]) type = @"ECSBlankView";
    
    Class class = NSClassFromString(type);
    
    UIView *view = [class alloc];
    [view.ecsAttributes addEntriesFromDictionary:attributes];
    ECS_BoxAttribute(view, context);
    //如果 view 具有id 则将其注册入 context
    if (attributes[@"id"] && ![attributes[@"id"] isEmpty])
        [context evaluateScript:[[NSString alloc] initWithFormat:@"var %@ = '%@';",attributes[@"id"], view._id]];
    view = [view init];
    
    //如果有 subView
    if ([view.ecsAttributes[@"subviews"] count])
        for (NSDictionary *subAttributes in view.ecsAttributes[@"subviews"])
            [view addSubview:[self viewWithAttributes:subAttributes context:context]];
    
    return view;
}

@end

NSString *NSStringFromECS_UIViewAlignMode(ECS_UIViewAlignMode align)
{
    return [[NSString alloc] initWithFormat:@"%li",align];
}
ECS_UIViewAlignMode ECS_UIViewAlignModeFromString(NSString *align)
{
    return [align integerValue];
}

#import "ECSUIDelegate+ECSUIAttributesParser.h"
@implementation ECSUIAttributesParser

//解析默认属性
+ (void)parseAttributeForView:(UIView *)view
{
    NSDictionary *defaultAttributesParser = [self defaultAttributForView:view.class];
    NSMutableDictionary *defaultAttributes = [NSMutableDictionary new];
    [defaultAttributesParser enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
        id attributeValue = view.ecsAttributes[key];
        if (!attributeValue || [attributeValue isEmpty]) attributeValue = value[0];
        if (!attributeValue || [attributeValue isEmpty]) return ;
        
        [defaultAttributes setObject:attributeValue forKey:key];
    }];
    
    [self parseAttributes:defaultAttributes forView:view];
}

//解析设置view的属性,并调用相应的委托
+ (id)parseAttributes:(id)attributes forView:(UIView *)view
{
    if ([attributes isKindOfClass:[NSDictionary class]]) {
        NSDictionary *defaultAttributes = [self defaultAttributForView:view.class];
        for (NSString *attributeName in attributes) {
            id value = attributes[attributeName];
            if (!value || [value isEmpty]) continue;
            
            //属性预处理
            id attributeValue = value;
            id (^ attributeHandler)(id) = nil;
            NSString *attributeKey = nil;
            
            //分析 attributeKey 与 attributeHandler
            for (int i = 1; i <= 2; i ++) {
                if ([defaultAttributes[attributeName] count] > i){
                    if ([defaultAttributes[attributeName][i] isKindOfClass:[NSString class]])
                        attributeKey = defaultAttributes[attributeName][i];
                    else if ([defaultAttributes[attributeName][i] isKindOfClass:NSClassFromString(@"NSBlock")])
                        attributeHandler = defaultAttributes[attributeName][i];
                    else
                        @throw [[NSException alloc] initWithName:@"ECSUIAttributesParser" reason:@"unrecognized attribute type ." userInfo:nil];
                }
            }
            
            attributeKey = attributeKey ? attributeKey : attributeName;
            attributeValue = attributeHandler ? attributeHandler(attributeValue) : attributeValue;
            
            //如果 view 没有名称为 attributeKey 的属性，需要手动处理该属性的存储
            if ([view respondsToSelector:NSSelectorFromString(attributeKey)]) {
                [view setValue:attributeValue forKey:attributeKey];
            }else{
                [self setValue:attributeValue forKey:attributeKey withView:view];
            }
            [[ECSUIDelegate defaultInstance] view:view didUpdateAttribute:attributeName];
        }
    }else if ([attributes isKindOfClass:[NSString class]]){
        if ([view respondsToSelector:NSSelectorFromString(attributes)])
            return [view valueForKey:attributes];
        else
            return [view.ecsAttributes objectForKey:attributes];
    }
    
    return nil;
}

+ (NSDictionary *)defaultAttributForView:(Class)class
{
    //获取默认属性
    static NSCache *classChainCache = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        classChainCache = [NSCache new];
    });
    NSMutableDictionary *defaultAttributes = [classChainCache objectForKey:NSStringFromClass(class)];
    if (!defaultAttributes) {
        defaultAttributes = [NSMutableDictionary new];
        NSMutableArray *classChain = [NSMutableArray arrayWithObject:class];
        while ([[classChain lastObject] respondsToSelector:@selector(autoLayoutAttributes)])
            [classChain addObject:[[classChain lastObject] superclass]];
        [classChain removeLastObject];
        
        while ([classChain lastObject]) {
            [defaultAttributes addEntriesFromDictionary:[(id<ECSAutoLayoutProtocol>)[classChain lastObject] autoLayoutAttributes]];
            [classChain removeLastObject];
        }
        [defaultAttributes addEntriesFromDictionary:[self autoLayoutAttributes]];
        [classChainCache setObject:defaultAttributes forKey:NSStringFromClass(class)];
    }
    return defaultAttributes;
}

//使用parser中定的block 设置 view 的属性
+ (void)setValue:(id)value forKey:(NSString *)key withView:(UIView *)view
{
    SEL selector = NSSelectorFromString(key);
    if (![self respondsToSelector:selector]) ECS_WrapObjectAttribute(view, value, [key UTF8String]);
    else{
        void (^handler)(UIView *view, id attribute) = objc_msgSend(self, selector);
        handler(view, value);
    }
}

#pragma mark- border
+ (void (^)(UIView *view, NSDictionary *border))border
{
    return ^(UIView *view, NSDictionary *border){
        if (!border || [border isEmpty]) return ;
        if (border[@"borderColor"]) view.layer.borderColor = [[UIColor colorWithScript:border[@"borderColor"]] CGColor];
        if (border[@"borderWidth"]) view.layer.borderWidth = [border[@"borderWidth"] floatValue];
        if (border[@"cornerRadius"]) view.layer.cornerRadius = [border[@"cornerRadius"] floatValue];
    };
}
+ (NSDictionary *)autoLayoutAttributes
{
    static NSDictionary *attributes = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        attributes = @{@"backgroundColor":@[NSNull.null,@"backgroundColor",
                                            ^UIColor *(NSString *script){
                                                return [UIColor colorWithScript:script];
                                            }],
                       @"alpha":@[@(1)],
                       @"size":@[NSNull.null,
                                 ^NSValue *(NSDictionary *size){
                                     return [NSValue valueWithCGSize:CGSizeMake([size[@"width"] floatValue],
                                                                                [size[@"height"] floatValue])];
                                 }],
                       @"border":@[NSNull.null],
                       @"align":@[@"left|top", ECS_UIViewAlignKey,
                                  ^NSString *(NSString *align){
                                      ECS_UIViewAlignMode (^aligmParser)(char flag) = ^ECS_UIViewAlignMode (char flag){
                                          switch (flag) {
                                              case 'l': return ECS_UIViewAlignModeLeft;
                                              case 'r': return ECS_UIViewAlignModeRight;
                                              case 't': return ECS_UIViewAlignModeTop;
                                              case 'b': return ECS_UIViewAlignModeBottom;
                                              case 'c': return ECS_UIViewAlignModeLeft | ECS_UIViewAlignModeRight | ECS_UIViewAlignModeTop | ECS_UIViewAlignModeBottom;
                                          }
                                          return 0;
                                      };
                                      ECS_UIViewAlignMode alignMode = 0;
                                      for (NSString *flag in [[align stringByReplacingOccurrencesOfString:@" " withString:@""] componentsSeparatedByString:@"|"]) {
                                          alignMode |= flag.length ? aligmParser([flag UTF8String][0]) : 0;
                                      }
                                      //默认 left top
                                      alignMode |= !(alignMode & ECS_UIViewAlignModeLeft) && !(alignMode & ECS_UIViewAlignModeRight) ? ECS_UIViewAlignModeLeft : 0;
                                      alignMode |= !(alignMode & ECS_UIViewAlignModeTop) && !(alignMode & ECS_UIViewAlignModeBottom) ? ECS_UIViewAlignModeTop : 0;
                                      return NSStringFromECS_UIViewAlignMode(alignMode);
                                  }
                                  ],
                       @"margin":@[NSNull.null, ECS_UIViewMarginKey,
                                   ^NSString *(id margin){
                                       return NSStringFromECS_Margin([margin isKindOfClass:[NSDictionary class]]
                                                                     ? UIEdgeInsetsMake([margin[@"top"] floatValue],
                                                                                        [margin[@"left"] floatValue],
                                                                                        [margin[@"bottom"] floatValue],
                                                                                        [margin[@"right"] floatValue])
                                                                     :UIEdgeInsetsMake([margin floatValue],
                                                                                       [margin floatValue],
                                                                                       [margin floatValue],
                                                                                       [margin floatValue]));
                                   }],
                       @"padding":@[NSNull.null, ECS_UIViewPaddingKey,
                                    ^NSString *(id margin){
                                        return NSStringFromECS_Margin([margin isKindOfClass:[NSDictionary class]]
                                                                      ? UIEdgeInsetsMake([margin[@"top"] floatValue],
                                                                                         [margin[@"left"] floatValue],
                                                                                         [margin[@"bottom"] floatValue],
                                                                                         [margin[@"right"] floatValue])
                                                                      :UIEdgeInsetsMake([margin floatValue],
                                                                                        [margin floatValue],
                                                                                        [margin floatValue],
                                                                                        [margin floatValue]));
                                    }]
                       };
    });
    return attributes;
}
@end


@implementation UIView (ECSUIBuilder)

+ (void)load
{
    Method initWithFrame = class_getInstanceMethod([UIView class], @selector(initWithFrame:));
    Method _ecsInitWithFrame = class_getInstanceMethod([UIView class], @selector(_ecsInitWithFrame_:));
    Method _initWithFrame_ECS = class_getInstanceMethod([UIView class], @selector(_initWithFrame_ECS:));
    
    method_exchangeImplementations(initWithFrame, _ecsInitWithFrame);
    method_exchangeImplementations(_initWithFrame_ECS, initWithFrame);
}

- (id)_initWithFrame_ECS:(CGRect)frame
{
    //该方法的 imp 在 load 之后将移交给 initWithFrame: 方法
    self = [self _ecsInitWithFrame_:frame];
    //解析设置 ecsAttributes 中的属性
    if ([self conformsToProtocol:@protocol(ECSAutoLayoutProtocol)])
        [ECSUIAttributesParser parseAttributeForView:self];
    return self;
}


- (id)_ecsInitWithFrame_:(CGRect)frame
{
    //空实现，load 之后，imp 将被替换为 initWithFrame: 方法的 imp
    return nil;
}
@end